using System;
using System.Collections.Generic;
using System.Linq;
using org.in2bits.MyXls;
using OpenSource.SpreadsheetFactory.Internal;

namespace OpenSource.SpreadsheetFactory.Internal.Xls
{
    internal sealed class XlsGenerator<T> : SpreadsheetGenerator<T>
    {
        internal XlsGenerator(IEnumerable<T> source) : base(source)
        {
        }

        private static int ColumnMaxWidth(ExcelRowCollection rowCollection, int column)
        {
            int maxWidth = 0;
            foreach (Row row in rowCollection)
            {
                Cell cell = row.GetCell((ushort) (column + 1));
                double fontWidthGuess = cell.Font.Height * 0.7;
                int length = cell.Value.ToString().Length;
                int widthGuess = Convert.ToInt32((double) ((fontWidthGuess * length) * 1.0));
                if (maxWidth < widthGuess)
                {
                    maxWidth = widthGuess;
                }
            }
            return (maxWidth / 12);
        }

        private void FillWorksheet(Worksheet worksheet, XlsDocument document)
        {
            this.GenerateHeader(worksheet);
            this.GenerateBody(worksheet);
            XlsGenerator<T>.ResizeColumns(worksheet, document);
        }

        private void GenerateBody(Worksheet worksheet)
        {
            int nextRow = 2;
            foreach (T item in Source)
            {
                int currentRow = nextRow++;
                int nextColumn = 1;
                foreach (Column<T> column in Columns)
                {
                    object value = column.GetColumnValue(item);
                    Cell cell = worksheet.Cells.Add(currentRow, nextColumn++, column.GetColumnValue(item));
                    if (value is DateTime)
                    {
                        cell.Format = "[$-F800]dddd, mmmm dd, yyyy";
                    }
                }
            }
        }

        private void GenerateHeader(Worksheet worksheet)
        {
            int nextColumn = 1;
            foreach (Column<T> column in Columns)
            {
                Cell cell = worksheet.Cells.Add(1, nextColumn++, column.Title);
                cell.Font.Weight = FontWeight.Bold;
                cell.HorizontalAlignment = HorizontalAlignments.Centered;
                cell.VerticalAlignment = VerticalAlignments.Centered;
            }
        }

        internal sealed override byte[] GenerateSpreadsheet()
        {
            XlsDocument document = new XlsDocument();
            this.FillWorksheet(document.Workbook.Worksheets.Add(Title), document);
            return document.Bytes.ByteArray;
        }

        private static void ResizeColumns(Worksheet worksheet, XlsDocument document)
        {
            ExcelRowCollection rowCollection = new ExcelRowCollection(worksheet);
            ushort minColumnNumber = rowCollection.Min<Row, ushort>(r => r.MinCellCol);
            ushort maxColumnNumber = (ushort)(rowCollection.Max<Row, ushort>(r => r.MaxCellCol) + 1);
            ColumnInfo[] columnInfos = new ColumnInfo[maxColumnNumber - minColumnNumber];
            for (ushort i = 0; i < columnInfos.Length; i = (ushort) (i + 1))
            {
                columnInfos[i] = new ColumnInfo(document, worksheet) { ColumnIndexStart = (ushort) ((minColumnNumber + i) - 1), ColumnIndexEnd = (ushort) ((minColumnNumber + i) - 1), Width = (ushort) (0x20 * XlsGenerator<T>.ColumnMaxWidth(rowCollection, i)) };
                worksheet.AddColumnInfo(columnInfos[i]);
            }
        }
    }
}

